package net.seabook.games.tetris.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;

import net.seabook.games.tetris.model.Piece;
import net.seabook.games.tetris.model.PieceGenerator;
import net.seabook.games.tetris.model.SettingSystem;
import net.seabook.games.tetris.model.TetrisBoard;

public class CanvasPanel extends JPanel {
	public static final int SPEED = 1000;

	private Piece piece;
	private TetrisBoard tBoard;

	private GoLeftAction goLeft;
	private GoRightAction goRight;
	private GoDownAction goDown;
	private RotateAction rotate;

	private PieceGenerator generator;

	private SettingSystem scoreSystem;

	private static final long serialVersionUID = 1L;

	public CanvasPanel(Piece block, TetrisBoard board) {
		this.piece = block;
		this.tBoard = board;
		this.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
		goLeft = new GoLeftAction(piece);
		goRight = new GoRightAction(piece);
		goDown = new GoDownAction(piece);
		rotate = new RotateAction(piece);
		setupKeybindings();
		worker.execute();
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		piece.drawSelf(g);
		tBoard.drawBoard(g);
	}

	@Override
	public Dimension getPreferredSize() {
		return new Dimension(TetrisBoard.BOARD_WIDTH, TetrisBoard.BOARD_HEIGHT);
	}

	SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
		@Override
		protected Void doInBackground() throws Exception {

			while (true) {
				if (tBoard.isGameOver()) {
					gameOver();
					return null;
				}

				if (tBoard.getSettingSystem().isStopped()) {
					continue;
				}

				Thread.sleep(scoreSystem.getLevelSpeed());
				if (!piece.isDead()) {
					piece.moveDown();
				} else {
					generator.shiftPiece();
					piece = generator.getPiece();
					goLeft.piece = piece;
					goRight.piece = piece;
					goDown.piece = piece;
					rotate.piece = piece;
				}
				repaint();
				
			}
		}

	};
	
	public void gameOver() {
		JOptionPane.showMessageDialog(this, "Game Over!!!");

	}

	private void setupKeybindings() {
		getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
				KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
		getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
				KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight");
		getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
				KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "rotate");
		getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
				KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "goDown");

		getActionMap().put("goLeft", getGoLeft());
		getActionMap().put("goRight", getGoRight());
		getActionMap().put("rotate", getRotate());
		getActionMap().put("goDown", getGoDown());
	}

	private class GoLeftAction extends AbstractAction {
		private Piece piece;

		public GoLeftAction(Piece piece) {
			this.piece = piece;
		}

		@Override
		public void actionPerformed(ActionEvent event) {
			if (!this.piece.isDead())
				this.piece.moveLeft();
			else
				this.piece.dipose();
			repaint();
		}
	};

	private class GoRightAction extends AbstractAction {
		private Piece piece;

		public GoRightAction(Piece piece) {
			this.piece = piece;
		}

		@Override
		public void actionPerformed(ActionEvent event) {
			if (!this.piece.isDead())
				this.piece.moveRight();
			else
				this.piece.dipose();
			repaint();
		}
	};

	private class GoDownAction extends AbstractAction {
		private Piece piece;

		public GoDownAction(Piece piece) {
			this.piece = piece;
		}

		@Override
		public void actionPerformed(ActionEvent event) {
			if (!this.piece.isDead())
				this.piece.moveDown();
			else
				this.piece.dipose();
			repaint();
		}
	};

	private class RotateAction extends AbstractAction {
		private Piece piece;

		public RotateAction(Piece piece) {
			this.piece = piece;
		}

		@Override
		public void actionPerformed(ActionEvent event) {
			if (!this.piece.isDead())
				this.piece.rotatePiece();
			else
				this.piece.dipose();
			repaint();
		}
	}

	public GoLeftAction getGoLeft() {
		return goLeft;
	}

	public GoRightAction getGoRight() {
		return goRight;
	}

	public GoDownAction getGoDown() {
		return goDown;
	}

	public RotateAction getRotate() {
		return rotate;
	}

	public Piece getPiece() {
		return piece;
	}

	public void setPiece(Piece piece) {
		this.piece = piece;
	}

	public TetrisBoard gettBoard() {
		return tBoard;
	}

	public void settBoard(TetrisBoard tBoard) {
		this.tBoard = tBoard;
	}

	public PieceGenerator getGenerator() {
		return generator;
	}

	public void setGenerator(PieceGenerator generator) {
		this.generator = generator;
	}

	public SettingSystem getScoreSystem() {
		return scoreSystem;
	}

	public void setScoreSystem(SettingSystem scoreSystem) {
		this.scoreSystem = scoreSystem;
	}

}
